#include "Screen.h"
#include <iostream>
using namespace std;

#define scIter map<screen*, int*>::iterator

//screen---------------------------------------------------
//constructors---------------
screen::screen(int w, int h) {
    //set up cairo and drawing surface
    drawSurface = NULL;
    cairosurf = NULL;

    drawSurface = SDL_CreateRGBSurface(SDL_SWSURFACE,
            w, h, 32,
            SDL_GetVideoInfo()->vfmt->Rmask,
            SDL_GetVideoInfo()->vfmt->Gmask,
            SDL_GetVideoInfo()->vfmt->Bmask,
            SDL_GetVideoInfo()->vfmt->Amask);
    
    cairosurf = cairo_image_surface_create_for_data(
            (unsigned char*) drawSurface->pixels,
            CAIRO_FORMAT_RGB24,
            drawSurface->w,
            drawSurface->h,
            drawSurface->pitch);

    //size variables
    drawPosition.x = 0;
    drawPosition.y = 0;
    drawPosition.w = w;
    drawPosition.h = h;

    screenSize.x = 0;
    screenSize.y = 0;
    screenSize.w = w;
    screenSize.h = h;

    //set bg info
    bgImg = NULL;
    bgCol = SDL_MapRGBA(SDL_GetVideoSurface()->format, 0, 0, 0, 1);

    //set window info
    window = NULL;

    windowPosition.x = -1;
    windowPosition.y = -1;
    windowPosition.w = -1;
    windowPosition.h = -1;
    cout << "Fuck--"; cout.flush();
}
screen::~screen() {
    SDL_FreeSurface(drawSurface);
}
//access---------------------
bool screen::getVisible(){
    return visible;
}
cairo_surface_t* screen::getCairoSurface(){
    return cairosurf;
}
screen* screen::getChild(int c){
    int i = 0;
    scIter scritr = children.begin();
    while(scritr != children.end()){
        if(i == c){
            return scritr->first;
        }
        i++;
        scritr++;
    }
    return NULL;
}
int screen::getWidth(){
    return windowPosition.w;
}
int screen::getHeight(){
    return windowPosition.h;
}
//screen parenting-----------
void screen::addChild(screen* s, int x, int y,  int w, int h){
    int* pos = new int[4];
    pos[0] = x;
    pos[1] = y;
    pos[2] = w;
    pos[3] = h;
    children[s] = pos;
    cout << "Adding a child at : " << x << ", " << y << ", " << w << ", " << h << endl;
}
void screen::removeChild(screen* s){
    children.erase(s);
}
void screen::removeChild(int i){
    removeChild(getChild(i));
}
//manipulation---------------
void screen::addImage(image* i, int xPos, int yPos) {
    if (i == NULL) return;
    i->move(xPos, yPos);
    images.push_back(i);
    i->setDrawSurface(drawSurface);
    i->setDrawSurface(cairosurf);
}
void screen::setBackground(Uint32 r, Uint32 g, Uint32 b) {
    bgCol = SDL_MapRGBA(SDL_GetVideoSurface()->format, r, g, b, 1);
}
void screen::setBackground(image* bgImage) {
    bgImg = bgImage;
}
void screen::draw() {
    draw(window);
}
void screen::draw(SDL_Surface* w){
    //conditionals------
    if(!visible) return;
    if(w == NULL) return;
    //conditionals======

    cout << "drawing a window--------------------" << endl;
    cout << "portion drawn : " << drawPosition.x << " " << drawPosition.y << " " << drawPosition.w << " " << drawPosition.h << endl;
    cout << "drawing a windo to : " << windowPosition.x << " " << windowPosition.y << " " << windowPosition.w << " " << windowPosition.h << endl;

    //draw background
    SDL_FillRect(drawSurface, &screenSize, bgCol);
    
    list<image*>::iterator imgitr;
    for (imgitr = images.begin(); imgitr != images.end(); imgitr++) {
        (*imgitr)->draw();
    }

    scIter scritr;
    for(scritr = children.begin(); scritr != children.end(); scritr++){
        (scritr->first)->draw(drawSurface);
    }

    SDL_BlitSurface(drawSurface, &drawPosition, w, &windowPosition);
    cout << "drawing a window====================" << endl;
}
//view manipulation----------
void screen::scrollDrawPosition(int x, int y) {
    drawPosition.x += x;
    drawPosition.y += y;
}
void screen::setDrawPosition(int x, int y) {
    drawPosition.x = x;
    drawPosition.y = y;
}
void screen::setWindowPosition(int x, int y, int w, int h) {
    //window info
    windowPosition.x = x;
    windowPosition.y = y;
    windowPosition.w = w;
    windowPosition.h = h;
    //map info
    drawPosition.w = w;
    drawPosition.h = h;
}
void screen::setVisible(bool isVisible){
    visible = isVisible;
}
//events---------------------
void screen::onUpdate(float timeElapsed) {
    list<updateHandler*>::iterator itr = updateHandlers.begin();

    while (itr != updateHandlers.end()) {
        (*itr)->onUpdate(timeElapsed);
        itr++;
    }

    draw();
}
void screen::addUpdateHandler(updateHandler* uh) {
    updateHandlers.push_back(uh);
}
void screen::removeUpdateHandler(updateHandler* uh) {
    updateHandlers.remove(uh);
}
void screen::addEventHandler(eventHandler* e) {
    eventHandlers.push_back(e);
}
void screen::removeEventHandler(eventHandler* e) {
    eventHandlers.remove(e);
}
bool screen::onEvent(SDL_Event* e) {
    list<eventHandler*>::iterator itr;
    for (itr = eventHandlers.begin(); itr != eventHandlers.end(); itr++) {
        if ((*itr)->onEvent(e)) return true;
    }
    return false;
}
//activation routines--------
void screen::onActivate(SDL_Surface* s) {
    cout << "activateing a window.\n";
    window = s;

    scIter scritr;
    int* pos;
    for(scritr = children.begin(); scritr != children.end(); scritr++){
        pos = scritr->second;
        cout << "activating child at : " << pos[0] << " " << pos[1] << " " << pos[2] << " " << pos[3] << endl;
        scritr->first->setWindowPosition(pos[0], pos[1], pos[2], pos[3]);
        scritr->first->onActivate(drawSurface);
    }
}
void screen::onDeactivate() {
    cout << "deactivating a window.\n";
    if (window == NULL) return;

    scIter scritr;
    for(scritr = children.begin(); scritr != children.end(); scritr++){
        (scritr->first)->onDeactivate();
    }

    Uint32 BlackColor = SDL_MapRGBA(SDL_GetVideoSurface()->format, 0, 0, 0, 1);
    SDL_FillRect(window, NULL, BlackColor);
    window = NULL;
}
//screen===================================================
//screenManager--------------------------------------------
//constructors----------
screenManager::screenManager(SDL_Surface* window) {
    parent = window;
    activeScreen = NULL;
}
screenManager::screenManager() {
    parent = SDL_GetVideoSurface();
    activeScreen = NULL;
}
screenManager::~screenManager() {
    map<string, screen*>::iterator itr;
    for(itr = screenCatalog.begin(); itr != screenCatalog.end(); itr++){
        delete itr->second;
    }
}
//access----------------
screen* screenManager::getScreen(string screenName) {
    if (screenCatalog.find(screenName) != screenCatalog.end()) {
        return screenCatalog[screenName];
    }
    return NULL;
}
screen* screenManager::getActiveScreen() {
    return activeScreen;
}
//manipulation----------
bool screenManager::registerScreen(string screenName, screen* scr) {
    if (screenCatalog.find(screenName) == screenCatalog.end()) {
        screenCatalog[screenName] = scr;
        return true;
    }
    return false;
}
screen* screenManager::unregisterScreen(string screenName) {
    screen* scr = NULL;
    if (screenCatalog.find(screenName) != screenCatalog.end()) {
        scr = screenCatalog[screenName];
        screenCatalog.erase(screenName);
    }
    return scr;
}
//activations-----------
bool screenManager::activateScreen(screen* scr) {
        activeScreen = scr;
        activeScreen->onActivate(parent);
        activeScreen->draw();
        return true;
}
bool screenManager::activateScreen(string screenName) {
    if (screenCatalog.find(screenName) != screenCatalog.end()) {
        return activateScreen(screenCatalog[screenName]);
    }
    return false;
}
bool screenManager::deactivateScreen(string screenName) {
    if (screenCatalog.find(screenName) != screenCatalog.end()) {
        return activateScreen(screenCatalog[screenName]);
    }
    return false;
}
//iterators-------------
screenManIterator screenManager::begining() {
    return screenCatalog.begin();
}
screenManIterator screenManager::end() {
    return screenCatalog.end();
}
//screenManager===============================================
